using System;
using System.Globalization;
using System.Windows.Data;

namespace FreshMeat.Xaml
{
#if !SILVERLIGHT
   [System.Windows.Markup.MarkupExtensionReturnType(typeof(IValueConverter))]
#endif
   public class MathExtension : System.Windows.Markup.MarkupExtension, IValueConverter
   {
      static MathExtension singleton;

      public override object ProvideValue(IServiceProvider serviceProvider)
      {
         return singleton ?? (singleton = new MathExtension());
      }

      public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
      {
         if (value == null)
            return null;

         var intResult = value is int;
         var doubleResult = value is double;

         if (!intResult && !doubleResult)
            return value;

         if (parameter == null)
            return value;

         var expression = parameter as string;
         if (expression == null)
            return value;
         
         expression = expression.Replace(" ", "");
         if (expression.Length < 2) // shortest possible valid expression, e.g. "+2"
            return value;
         
         var op = expression[0];
         var operandText = expression.Substring(1);
         if (doubleResult || operandText.IndexOf('.') >= 0)
         {
            double doubleOp;
            if (!double.TryParse(operandText, out doubleOp))
               return value;

            var valueAsDouble = doubleResult ? (double)value : System.Convert.ToDouble(value);
            var result = DoubleMath(valueAsDouble, op, doubleOp);
            if (intResult)
               return (int)result;
            return result;
         }
         else
         {
            int intOp;
            if (!int.TryParse(operandText, out intOp))
               return value;

            var result = IntMath((int)value, op, intOp);
            return result;
         }
      }

      static double DoubleMath(double a, char op, double b)
      {
         switch (op)
         {
            case '+':
               return a + b;
            case '-':
               return a - b;
            case '*':
               return a * b;
            case '/':
               return a / b;
            case '%':
               return a % b;
            default:
               return a;
         }
      }

      static int IntMath(int a, char op, int b)
      {
         switch (op)
         {
            case '+':
               return a + b;
            case '-':
               return a - b;
            case '*':
               return a * b;
            case '/':
               return a / b;
            case '%':
               return a % b;
            default:
               return a;
         }
      }

      public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
      {
         return !(bool)value;
      }
   }
}